package com.googlecode.scup.parser.automat;

import com.googlecode.scup.grammar.grammarspart.AutomatRule;
import com.googlecode.scup.grammar.grammarspart.Symbol;
import com.googlecode.scup.grammar.Grammar;

import java.util.List;
import java.util.ArrayList;

public class AutomatState {
    private List<AutomatRule> rules = null;
    private Grammar grammar = null;
    private List<Symbol> terminals = null;
    private List<Symbol> nonterminals = null;

    public AutomatState(List<AutomatRule> rules, Grammar grammar) {
        this.rules = rules;
        this.grammar = grammar;
        makeClosure();
        terminals = new ArrayList<Symbol>();
        nonterminals = new ArrayList<Symbol>();
        makeDivision();
    }

    private void makeClosure() {
        List<AutomatRule> automatRules = null;
        Symbol pointSymbol = null;
        for (int i = 0; i < rules.size(); ++i) {
            pointSymbol = rules.get(i).getPointSymbol();
            if ((pointSymbol != null) && (!pointSymbol.isTerminal())){
                automatRules = AutomatRule.createAutomatRules(grammar.getRule(pointSymbol));
                for (AutomatRule rule : automatRules) {
                    if (!rules.contains(rule)) {
                        rules.add(rule);
                    }
                }
            }
        }
    }

    private void makeDivision() {
        Symbol pointSymbol = null;
        for(AutomatRule rule : rules) {
            pointSymbol = rule.getPointSymbol();
            if (pointSymbol != null) {
                if (pointSymbol.isTerminal()) {
                    terminals.add(pointSymbol);
                } else {
                    nonterminals.add(pointSymbol);
                }
            }
        }
    }

    public List<Symbol> getTerminals() {
        return terminals;
    }

    public List<Symbol> getNonTerminals() {
        return nonterminals;
    }

    public List<Symbol> getAllSymbols() {
        List<Symbol> result = new ArrayList<Symbol>();
        result.addAll(terminals);
        result.addAll(nonterminals);
        return result;
    }

    public List<AutomatRule> getTransitionRule(Symbol symbol) {
        List<AutomatRule> result = new ArrayList<AutomatRule>();
        Symbol pointSymbol = null;
        for (AutomatRule rule : rules) {
            pointSymbol = rule.getPointSymbol();
            if ((pointSymbol != null) && (pointSymbol.equals(symbol))) {
                result.add(rule.getNext());
            }
        }
        return result;
    }

    public List<AutomatRule> getEndRules() {
        List<AutomatRule> result = new ArrayList<AutomatRule>();
        for (AutomatRule rule : rules) {
            if (rule.getPointSymbol() == null) {
                result.add(rule);
            }
        }
        return result;
    }

    public String toString() {
        StringBuilder result = new StringBuilder();
        for(AutomatRule rule : rules) {
            result.append(rule);
            result.append('\n');
        }
        return result.toString();
    }

    public boolean equals(Object obj){
        if (! (obj instanceof AutomatState)) {
            return false;
        }
        AutomatState state = (AutomatState) obj;
        if (this.rules.size() != state.rules.size()) {
            return false;
        }
        for (int i = 0; i < this.rules.size(); ++i) {
            if (! rules.get(i).equals(state.rules.get(i))) {
                return false;
            }
        }
        return true;
    }
}
